package com.wx.task.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * 自定义线程池
 * 线程池的各个参数的设置都是经过压测得到的一个最优值
 */
@Configuration
public class ThreadPoolTaskConfig {

    /**
     * 核心线程数
     */
    private static final int CORE_POOL_SIZE = 3;

    /**
     * 最大线程数
     */
    private static final int MAX_POOL_SIZE = CORE_POOL_SIZE * 4 < 256 ? 256 : CORE_POOL_SIZE * 4;

    /**
     * 允许线程空闲时间 (单位秒)
     */
    private static final int KEEP_ALIVE_TIME = 100;

    /**
     * 阻塞队列的最大容量
     */
    private static final int QUEUE_CAPACITY = 100;

    /**
     * 用来设置线程池关闭的时候等待所有任务都完成再关闭线程池。
     * 要等待所有的任务完成，那么需要等待多长时间？等待时间太长也不行啊，是不是？那么有一个参数可以设置最大等待时间: AWAIT_TERMINATION
     */
    private static final boolean WAIT_FOR_TASKS_TO_COMPLETE_ON_SHUTDOWN = true;

    /**
     * 线程池要关闭了，但是任务还没执行完，等待任务的执行时间，如果超过这个时间还没有销毁就强制销毁
     */
    private static final int AWAIT_TERMINATION = 60;

    /**
     * 线程池名前缀
     */
    private static final String THREAD_NAME_PREFIX = "TaskAsync-Service-";

    /**
     * 是否允许 [核心线程] 超时销毁
     */
    private static final boolean ALLOW_CORE_THREAD_TIMEOUT = true;

    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(CORE_POOL_SIZE);
        taskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
        taskExecutor.setKeepAliveSeconds(KEEP_ALIVE_TIME);
        taskExecutor.setQueueCapacity(QUEUE_CAPACITY);
        taskExecutor.setThreadNamePrefix(THREAD_NAME_PREFIX);
        taskExecutor.setWaitForTasksToCompleteOnShutdown(WAIT_FOR_TASKS_TO_COMPLETE_ON_SHUTDOWN);
        taskExecutor.setAwaitTerminationSeconds(AWAIT_TERMINATION);
        taskExecutor.setAllowCoreThreadTimeOut(ALLOW_CORE_THREAD_TIMEOUT);
        // 拒绝策略: 使用调用者线程来执行任务
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 初始化线程池
        taskExecutor.initialize();
        return taskExecutor;
    }

}
